﻿using System;
using System.IO;
using System.Runtime.Serialization;
using System.Text;
using System.Xml;
using System.Xml.Serialization;
using Polenter.Serialization;

namespace Elderos.Utils.Serialization
{
	public static class XSerializer
	{
		public static string SerializeObject(Object obj, Type serializerType = null, Encoding encoding = null)
		{
			if (serializerType == null)
				serializerType = typeof(XmlSerializer);
            if (encoding == null) encoding = Encoding.UTF8;
			using (var memoryStream = new MemoryStream())
			{
			    if (serializerType == typeof(XmlSerializer))
			    {
			        var xs = new XmlSerializer(obj.GetType());
			        xs.Serialize(memoryStream, obj);
			    }
			    else if (serializerType == typeof(DataContractSerializer))
			    {
			        var xs = new DataContractSerializer(obj.GetType());
			        xs.WriteObject(memoryStream, obj);
			    }
			    else if (serializerType == typeof(NetDataContractSerializer))
			    {
			        var xs = new NetDataContractSerializer();
			        xs.WriteObject(memoryStream, obj);
			    }
			    else if (serializerType == typeof(SharpSerializer))
			    {
			        var xs = new SharpSerializer();
			        xs.Serialize(obj, memoryStream);
			    }
			    else
			        throw new ArgumentException(string.Format("Invalid serializer type: {0}.", serializerType.Name),
			                                    "serializerType");

                memoryStream.Flush();

			    return ByteArrayToString(memoryStream.ToArray(), encoding);
			}
		}

		public static T DeserializeObject<T>(string objString, Type serializerType = null, Encoding encoding = null)
		{
			if (serializerType == null)
				serializerType = typeof(XmlSerializer);

            if (encoding == null) encoding = Encoding.UTF8;
		    using (var memoryStream = new MemoryStream(StringToByteArray(objString, encoding)))
            {
                Object obj;
                if (serializerType == typeof(XmlSerializer))
                {
                    var xs = new XmlSerializer(typeof(T));
                    
                    var xtr = new XmlTextReader(memoryStream);
                    obj = xs.Deserialize(xtr);
                }
                else if (serializerType == typeof(DataContractSerializer))
                {
                    var xs = new DataContractSerializer(typeof(T));
                    
                    obj = xs.ReadObject(memoryStream);
                }
                else if (serializerType == typeof(NetDataContractSerializer))
                {
                    var xs = new NetDataContractSerializer();

                    obj = xs.ReadObject(memoryStream);
                }
                else if (serializerType == typeof(SharpSerializer))
                {
                    var xs = new SharpSerializer();
                    obj = xs.Deserialize(memoryStream);
                }
                else
                    throw new ArgumentException(string.Format("Invalid serializer type: {0}.", serializerType.Name),
                                                "serializerType");
                return (T) obj;
            }
		}

		private static string ByteArrayToString(byte[] characters, Encoding encoding = null)
		{
            if (encoding == null) encoding = Encoding.UTF8;
			return encoding.GetString(characters);
		}

		private static byte[] StringToByteArray(string xmlString, Encoding encoding = null)
		{
			if (encoding == null) encoding = Encoding.UTF8;
			return encoding.GetBytes(xmlString);
		}
	}
}